package com.zhrj.exam.service.Impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zhrj.exam.entity.BladeUser;
import com.zhrj.exam.mapper.BladeUserMapper;
import com.zhrj.exam.service.UserService;
import com.zhrj.exam.tool.R;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RestTemplate restTemplate;
    
    @Resource
    private BladeUserMapper bladeUserMapper;

    @Resource
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Override
    public List<BladeUser> getUserInfo(String account) {
        String authToken =  stringRedisTemplate.opsForValue().get("token:" + account);
        if (authToken == null) {
            throw new RuntimeException("token未获取或已超时，请重新获取token");
        }

        String url = "http://localhost:80/blade-user/user-list";

        HttpHeaders headers = new HttpHeaders();
        headers.set("Blade-Auth", "Bearer " + authToken);
        headers.set("Content-Type", "application/json;charset=UTF-8");
        headers.set("Authorization","Basic c2FiZXI6c2FiZXJfc2VjcmV0");

        // 创建HttpEntity对象，可以传入null作为请求体因为这是一个GET请求
        HttpEntity<?> requestEntity = new HttpEntity<>(null, headers);

        try {
            // 发送GET请求并获取响应
            ResponseEntity<R<List<BladeUser>>> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    requestEntity,
                    new ParameterizedTypeReference<R<List<BladeUser>>>() {}
            );

            // 检查响应状态码
            if (response.getStatusCode().is2xxSuccessful()) {
                R<List<BladeUser>> result = response.getBody();
                if (result != null && result.isSuccess()) {
                    return result.getData();
                } else {
                    throw new RuntimeException("获取用户列表失败: " + (result != null ? result.getMsg() : "未知错误"));
                }
            } else {
                throw new RuntimeException("请求失败，状态码: " + response.getStatusCodeValue());
            }
        } catch (RestClientException e) {
            throw new RuntimeException("调用用户列表接口失败: " + e.getMessage(), e);
        }
    }

    @Override
    public PageInfo<BladeUser> getUserForPage(Integer pageNum, Integer pageSize) {
        Page<BladeUser> page = PageHelper.startPage(pageNum, pageSize);
        bladeUserMapper.selectList(null);
        return page.toPageInfo();
    }

    @Override
    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    @Async("taskExecutor")
    public void updateUserInfo() {
        log.info("开始更新用户信息");
        if (!stringRedisTemplate.hasKey("token:admin")) {
            log.info(String.valueOf(stringRedisTemplate.hasKey("token:admin")));
            throw new RuntimeException("token不存在或已过期，请重新获取");
        }


        List<BladeUser> remoteList = getUserInfo("admin");

        List<BladeUser> myList = bladeUserMapper.selectList(null);

        Map<Long, BladeUser> myMap = myList.stream()
                .collect(Collectors.toMap(BladeUser::getId, user -> user));

        // 遍历远程数据
        for (BladeUser remoteUser : remoteList) {
            BladeUser localUser = myMap.get(remoteUser.getId());

            if (localUser == null) {
                // 本地不存在，新增数据
                bladeUserMapper.insert(remoteUser);
            } else {
                // 本地存在，比较是否需要更新
                if (!remoteUser.equals(localUser)) {
                    // 数据不一致，更新本地数据
                    bladeUserMapper.updateById(remoteUser);
                }
            }
        }

    }

    @Override
    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    @Async("taskExecutor")
    public void exportUsersToMinio() {

        if (!stringRedisTemplate.hasKey("token:admin")) {
            throw new RuntimeException("token不存在或已过期，请重新获取");
        }

        List<BladeUser> list = getUserInfo("admin");
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String fileName = "user_export_" + date + "_" + System.currentTimeMillis() + ".xlsx";


        //  使用EasyExcel写入内存缓冲区
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ExcelWriter excelWriter = null;
        try {
            // 配置Excel写入器（自动应用实体类中的@ColumnWidth注解）
            excelWriter = EasyExcel.write(outputStream, BladeUser.class)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                    .build();

            // 写入数据到Sheet
            WriteSheet writeSheet = EasyExcel.writerSheet("用户列表")
                    .build();
            excelWriter.write(list, writeSheet);
        } finally {
            // 确保资源释放
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }

        // 上传到MinIO
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(
                                    new ByteArrayInputStream(outputStream.toByteArray()),
                                    outputStream.size(),
                                    -1)
                            .contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
                            .build());



        } catch (Exception e) {
            log.error("上传文件到MinIO失败", e);
//            return new AsyncResult<>("error: " + e.getMessage()); // 返回错误信息
            throw new RuntimeException("上传文件到MinIO失败", e);
        }


    }


    // 新增方法用于启动时调用
    public void initUpdateUserInfo() {
        updateUserInfo();
    }

    public void initExportUsersToMinio() {
        exportUsersToMinio();
    }
}
